This document describes the public API, which you can use to create extensions to GriefPrevention which add new features.  Before I get into the specifics, let me give you a few examples of often-requested features which, to my knowledge, have not yet been implemented by anyone.  If you want to make a big impact with a small project, these are the go-to areas!  If you publish one of these extensions on BukkitDev, please contact me and I'll add a link from my project to yours.

Claim Buy/Sell

I keep saying no to this because I'm developing an anti grief plugin, not a real estate plugin.  But it's a common ask.  Lots of people would use an extension that allowed them to use server money to buy and sell claims, or to lease subdivisions.

More Locks

Many have asked for wooden doors, trap doors, and fence gates to require /AccessTrust.  I've insisted that because players generally expect these to be openable (based on the Vanilla experience), players should just "earn" their privacy by finding some iron and building an iron door.  Nonetheless, some folks definitely want this.

Claim Flags

Sometimes, folks want to add special flags to their claims like "no monsters spawn here".  They can do this today by adding other plugins like WorldGuard, which are compatible with GriefPrevention, but it would be nice if they could just use one plugin (and an extension).  I think their flag ideas come mostly from Residence and WorldGuard, so you can look there for ideas.

Claim Entry/Exit Messages

I keep telling people NO, I won't do this because it's not anti-grief-related and it's expensive to constantly track player movement.  But folks want it, and they keep asking for it.  You could build an extension which adds some slash commands for naming claims, and displays enter/exit messages as players walk around.

Now the specifics!  Please note, these are the supported operations.  I've done my best to "hide" fields and methods which you shouldn't play with, but if you happen to notice something not discussed here, it's best not to fiddle with it.  If in doubt, at the very least look at my source code and comments before using something you're unfamiliar with in an extension.

Getting the Claim at a Location

Managing Permissions in a Claim

Creating a New Claim

Resizing or Moving a Claim

Extending a Claim Downward

Changing a Claim's Owner

Updating Other Claim Fields

Uniquely Identifying a Claim

Getting/Updating Player Data

Getting World and Claim Y Dimensions

This API allows you to query the vertical (Y-axis) boundaries for worlds and claims. This is particularly useful for extensions that need to understand claim boundaries for different claim types.

== World Y Boundaries ==

GriefPrevention.getWorldMinY(world) - gets the minimum Y coordinate (build limit) for the world
GriefPrevention.getWorldMaxY(world) - gets the maximum Y coordinate (build limit) for the world

Example:
    World world = player.getWorld();
    int minY = GriefPrevention.getWorldMinY(world);  // e.g., -64 in 1.18+
    int maxY = GriefPrevention.getWorldMaxY(world);  // e.g., 320 in 1.18+

== Claim Y Boundaries ==

claim.getMinY() - gets the minimum Y coordinate for the claim
claim.getMaxY() - gets the maximum Y coordinate for the claim
claim.getYHeight() - gets the vertical height of the claim in blocks
claim.containsY(y) - checks if a Y coordinate is within the claim's boundaries
claim.is3D() - checks if this is a 3D claim (respects custom Y boundaries)

Behavior by claim type:
- Main Claims: Always span world min to max Y (full height)
- Admin Claims: Always span world min to max Y (full height)
- 2D Subdivisions: Span world min to max Y (inherit from world)
- 3D Subdivisions: Use their own defined Y boundaries

Example:
    Claim claim = GriefPrevention.instance.dataStore.getClaimAt(location, true, null);
    if (claim != null) {
        int minY = claim.getMinY();
        int maxY = claim.getMaxY();
        int height = claim.getYHeight();
        boolean is3D = claim.is3D();
        
        if (is3D) {
            // This claim has custom Y boundaries
            player.sendMessage("This 3D claim spans Y " + minY + " to " + maxY);
        } else {
            // This claim spans the full world height
            player.sendMessage("This claim spans the full world height");
        }
    }

== Detailed Claim Y Information ==

For more detailed information, use the ClaimYInfo class:

claim.getYInfo() - returns a ClaimYInfo object with comprehensive Y boundary data

ClaimYInfo methods:
- getMinY() - minimum Y coordinate
- getMaxY() - maximum Y coordinate  
- getHeight() - vertical height in blocks
- is3D() - true if claim has custom Y boundaries
- isSubdivision() - true if this is a subdivision (has parent)
- isAdminClaim() - true if this is an admin claim
- getClaimType() - human-readable type: "Main Claim", "Admin Claim", "2D Subdivision", "3D Subdivision", "Admin 2D Subdivision", "Admin 3D Subdivision"

Example:
    Claim claim = GriefPrevention.instance.dataStore.getClaimAt(location, true, null);
    if (claim != null) {
        Claim.ClaimYInfo yInfo = claim.getYInfo();
        
        player.sendMessage("Claim Type: " + yInfo.getClaimType());
        player.sendMessage("Y Range: " + yInfo.getMinY() + " to " + yInfo.getMaxY());
        player.sendMessage("Height: " + yInfo.getHeight() + " blocks");
        
        if (yInfo.is3D()) {
            player.sendMessage("This is a 3D claim with custom vertical boundaries.");
        }
        
        // toString() provides a summary
        System.out.println(yInfo.toString());
        // Output: ClaimYInfo{type=3D Subdivision, minY=60, maxY=80, height=21}
    }

== Checking Y Containment ==

claim.containsY(y) - checks if a Y coordinate is within the claim's Y boundaries

For 3D claims, this checks against the actual Y boundaries.
For non-3D claims, this always returns true (Y is not enforced).

Example:
    int blockY = block.getY();
    if (claim.containsY(blockY)) {
        // The Y coordinate is within this claim's vertical boundaries
    }


Boundary Visualization API
==========================

As of v18.0.3, the boundary-visualization extension points originally developed on the `feature/gpapiaddon-workspace` branch are part of the supported public API. Addons can now:

- Trigger the same visuals GriefPrevention uses internally (claim outlines, conflict zones, nearby-claim sweeps).
- Listen for visualization events to mutate, replace, or cancel visuals before they are drawn.
- Provide entirely custom rendering pipelines (particles, BlockDisplay glow, packets, etc.) by implementing the supplied interfaces.

The relevant packages are:

- com.griefprevention.visualization        - rendering surface (Boundary, BoundaryVisualization, VisualizationStyle, VisualizationProvider, BlockBoundaryRenderer, VisualizationType)
- com.griefprevention.visualization.impl   - built-in providers (FakeBlockVisualization, LegacyFakeBlockVisualization, AntiCheatCompatVisualization, GlowingVisualization)
- com.griefprevention.events               - listenable events (BoundaryVisualizationEvent)

== Triggering a Visualization ==

The static helpers on BoundaryVisualization fire a BoundaryVisualizationEvent and apply the resulting visualization to the player. They are safe to call from main-thread code.

BoundaryVisualization.visualizeClaim(player, claim, type)
BoundaryVisualization.visualizeClaim(player, claim, type, block)
BoundaryVisualization.visualizeArea(player, boundingBox, type)
BoundaryVisualization.visualizeArea(player, boundingBox, type, height)
BoundaryVisualization.visualizeNearbyClaims(player, claims, height)

`type` is a VisualizationType:
    CLAIM, ADMIN_CLAIM, SUBDIVISION, SUBDIVISION_3D, ADMIN_CLAIM_3D,
    CONFLICT_ZONE, CONFLICT_ZONE_3D, INITIALIZE_ZONE, INITIALIZE_ZONE_3D

Example - show a player their claim outline at eye level:
    Claim claim = GriefPrevention.instance.dataStore.getClaimAt(player.getLocation(), true, null);
    if (claim != null) {
        VisualizationType type = claim.isAdminClaim()
                ? VisualizationType.ADMIN_CLAIM
                : VisualizationType.CLAIM;
        BoundaryVisualization.visualizeClaim(player, claim, type);
    }

Example - flash a conflict zone for a pending claim region:
    BoundingBox box = new BoundingBox(x1, y1, z1, x2, y2, z2);
    BoundaryVisualization.visualizeArea(player, box, VisualizationType.CONFLICT_ZONE);

Example - visualize every claim near a moderator:
    Set<Claim> nearby = GriefPrevention.instance.dataStore.getNearbyClaims(player.getLocation());
    BoundaryVisualization.visualizeNearbyClaims(player, nearby, player.getEyeLocation().getBlockY());

== Listening for BoundaryVisualizationEvent ==

BoundaryVisualizationEvent is a standard Bukkit PlayerEvent. The boundary collection is mutable, and the active VisualizationProvider can be swapped before the visualization is constructed.

Use cases:
- Add custom decorative boundaries (e.g. waypoints).
- Strip boundaries from claims your addon hides.
- Replace the default fake-block renderer with your own provider for specific players or regions.

Example - swap to a custom particle-based provider for one player:
    @EventHandler
    public void onVisualize(BoundaryVisualizationEvent event) {
        if (!event.getPlayer().hasPermission("myaddon.fancy")) return;
        event.setProvider((world, visualizeFrom, height) ->
                new MyParticleVisualization(world, visualizeFrom, height));
    }

Example - hide boundaries that belong to admin claims for a specific player:
    @EventHandler
    public void onVisualize(BoundaryVisualizationEvent event) {
        if (!event.getPlayer().hasPermission("myaddon.hideadmin")) return;
        event.getBoundaries().removeIf(b -> b.claim() != null && b.claim().isAdminClaim());
    }

== Implementing a Custom VisualizationProvider ==

A VisualizationProvider is a factory for BoundaryVisualization instances. The simplest path is to extend one of the built-in classes:

- BlockBoundaryVisualization / FakeBlockVisualization - 1.13+ fake-block outlines.
- LegacyFakeBlockVisualization                        - 1.8.8 NMS packet path.
- AntiCheatCompatVisualization                        - 1.13+ outlines that respect anticheat transparency rules.
- GlowingVisualization                                - 1.19.3+ BlockDisplay glow outlines.

Example - a custom provider that always uses glow on supported servers:
    public final class GlowOnlyProvider implements VisualizationProvider {
        @Override
        public @NotNull BoundaryVisualization create(
                @NotNull World world,
                @NotNull IntVector visualizeFrom,
                int height) {
            return new GlowingVisualization(world, visualizeFrom, height);
        }
    }

Register it per-call via the event:
    event.setProvider(new GlowOnlyProvider());

== Defining a Custom VisualizationStyle ==

VisualizationStyle is a key-addressable variant on top of VisualizationType. Built-in types are themselves styles. Addons may register their own styles for use with `BoundaryVisualization.visualizeClaim(player, claim, style)` and friends.

Implement the interface and (optionally) a BlockBoundaryRenderer if you want the built-in fake-block path to render your style:

    public final class MyClaimStyle implements VisualizationStyle {
        @Override public @NotNull String getKey() { return "myaddon:claim"; }
        @Override public @Nullable BlockBoundaryRenderer getBlockRenderer() {
            return MY_RENDERER; // or null to require a custom VisualizationProvider
        }
    }

Note: The keys intentionally use a plain `namespace:name` string instead of Bukkit's NamespacedKey so the same jar continues to load on legacy servers (1.8.8) where NamespacedKey does not exist.